#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//结构体的位段
// 位段的声明是和结构体类似的，也就是说，位段是基于结构体的
// 有两个不同
// 1.位段的成员必须是int,unsigned int 或者 signed int，在C99中
// 位段成员的类型也可以选择其他类型
// 2.位段的成员名后边有一个冒号和一个数字
//
//struct A
//{
//	int _a : 2; //2表示，a只占2个比特位
//	int _b : 5; //5表示，b只占5个比特位
//	int _c : 10;//10表示 c只占10个比特位
//	int _d : 30;//30表示 d只占30个比特位
//};
////A就是一个位段类型（位段中的位指的是二进制位）
//int main()
//{
//	printf("%zd\n", sizeof(struct A));
//
//	return 0;
//}


//位段的内存分配
//
//struct S
//{
//	char a : 3;
//	char b : 4;
//	char c : 5;
//	char d : 4;
//};
//
//struct S s = { 0 };
//
//int main()
//{
//	s.a = 10;//10的二进制表示为1010，但a成员只有3个比特位会发生截断
//	s.b = 12;//12的二进制表示为1100,
//	s.c = 3;//3的二进制表示为0011
//	s.d = 4;//4的二进制表示为0100
//	//所以赋值之后，s内的二进制表示为
//	//0110 0010 0000 0011 0000 0100
//	//6     2    0     3   0    4
//	printf("%zd\n", sizeof(struct S));//占3个字节
//	return 0;
//}
//位段的成员可以是int unsigned int signed int char类型
//位段的空间上是需要以4个字节(32个比特位)(int)或者1个字节(8个比特位)(char)的方式来开辟的
//位段开辟空间有很多不确定因素
//1.申请到的一块内存中，是从左到右还是从右到左来填入数据，是不确定的
//2.申请到的一块内存中，填完数据后，剩余的空间，不是足以下一个成员使用的时候
//是浪费还是继续使用，是不确定的
//在vs上，是从右向左使用，填完数据后，剩余的数据浪费掉


//跨平台性
//1.int位段被当成有符号数还是无符号数在不同编译器上是不一样的，所以是不确定的
//2.位段中最大位的数目不能确定(16位机器最大是16，32位机器最大32，如果写成27，在16位的机器就会出现问题)
//3.位段中的成员在内存中从左向右分配，还是从右向左分配，标准尚未定义(vs是从右向左分配的)
//4.当一个结构包含两个位段，第二个位段成员比较大，无法容纳于第一个位段剩余的位时，是舍弃剩余的位还是利于，这是不确定的


//总结：跟结构相比，位段可以达到同样的效果，并且可以很好的节省空间，但是存在跨平台的问题存在


//位段的应用：
//在网络协议中，IP数据报，很多的属性只需要几个bit位就可以描述，这里使用位段，就可以实现想要的效果，也能节省空间
//这样网络传输的数据报会小一些，对网络畅通有帮助

//位段使用的注意事项
//1.位段里面的类型需保持一致
//2.位段中存在几个成员共有同一个字节的情况，这样有些成员的起始地址并不是某个字节的起始位置，
//那么这些位置处是没有地址的，因为在内存中，是每个字节分配一个地址，一个字节内部的bit位是没有地址的
//所以不能对位段的成员使用&操作符，这样就不能直接用scanf给位段的成员输入值，只能是先输入放在一个变量中，然后赋值给位段的成员

struct A
{
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};

int main()
{
	struct A sa = { 0 };
	//scanf("%d", &sa.a);//错误，位段中的成员不能直接使用&操作符

	int b = 0;
	scanf("%d", &b);//right
	sa.a = b;
	return 0;
}
